The aim of this website is to report the ongoing geospatial data analysis for the CCRI’s Agricultural Transition: Great South West Partnership project. All of the tables and plots shown on this website can also be accessed as individual files HERE. The full R programming code used to perform the work is included in this report, and can be accessed by clicking on the “Code” buttons. If you are unfamiliar with R code, comments (in plain English) have been added to describe the operation of each code block, so it should be possible to follow the methodology.
This section shows the code and outputs for the analysis of Pillar 1 (P1) payments at county level (for the counties of Cornwall, Devon, Dorset, and Somerset)
Import and cleaning of the CAP Payments (data source: HERE)
Step 1 - Load code packages and import data
#> 1.1.1 Load libraries
library(tidyverse) # data munging and analysis
library(sf) # simple features for GIS
library(qgisprocess) # access to QGIS algorithms
library(here) # relative path management for reproducibility
library(lubridate) # for date string manipulation/conversion
library(janitor) # data cleaning functions
library(knitr) # report rendering with rmarkdown
library(ggplot2) # plots and visualisations
library(readxl) # import xls
library(scales) # for plot scale customisation
library(mapproj) # map zoom coords
library(leaflet) # interactive web maps
library(reshape2) # to reshape data (used for "melt" function)
library(units) # to convert from m2 to km2
#> 1.1.2 Import data (trimming white space)
#> "RPA" sheet
rpa.1 <- readxl::read_xlsx(here("In", "BPS_Glos", "2020_All_CAP_Search_Results_Data_P14.xlsx"), trim_ws = TRUE, sheet = "RPA")
#> "RPA2" sheet
rpa.2 <- readxl::read_xlsx(here("In", "BPS_Glos", "2020_All_CAP_Search_Results_Data_P14.xlsx"), trim_ws = TRUE, sheet = "RPA2")Step 2 - Data cleaning and pre-processing
#> 1.1.3 Data cleaning and pre-processing
#> Bind the two RPA tables together (they are split alphabetically by beneficiary name)
db <- rbind(rpa.1, rpa.2)
#> Remove duplicates
db <- db %>%
distinct()
#> Remove any empty records where all columns are "NA"
# Following filters rows with at least one column not "NA"
db <- janitor::remove_empty(db, which = "rows")
#> Select only relevant rcolumns
db <- db %>%
select("BeneficiaryCode", "PostcodePrefix_F202B", "TownCity_F202C", "Basic payment scheme", "Greening: practices beneficial for climate and environment") |>
arrange(desc(`Basic payment scheme`))Table 1.1.1 Full database on import = 88443 records (all England)
## Rows: 88,443
## Columns: 5
## $ BeneficiaryCode <dbl> NA, NA, N~
## $ PostcodePrefix_F202B <chr> "LN4", "S~
## $ TownCity_F202C <chr> "LINCOLN"~
## $ `Basic payment scheme` <dbl> 1929366.7~
## $ `Greening: practices beneficial for climate and environment` <dbl> 872521.2,~
Table 1.1.2 First 6 rows of database
## # A tibble: 6 x 5
## BeneficiaryCode PostcodePrefix_F202B TownCity_F202C `Basic payment scheme`
## <dbl> <chr> <chr> <dbl>
## 1 NA LN4 LINCOLN 1929367.
## 2 NA SN2 SWINDON 1838669.
## 3 NA CB2 Cambridge 975272.
## 4 NA NE71 WOOLER 969240.
## 5 NA LN5 LINCOLN 875713.
## 6 NA PE38 DOWNHAM MARKET 847869.
## # ... with 1 more variable:
## # `Greening: practices beneficial for climate and environment` <dbl>
The CAP Payments dataset reports payments at postcode district level, but postcode districts do not conform to administrative boundaries (e.g. counties, district unitary authorities). Our approach is to calculate the area of agricultural land (using Corine land cover data) within each postcode district, and to use this to calculate the P1 payments. For districts which straddle county boundaries, the area of agricultural land both inside and outside of the target county are calculated, and the P1 payments are calculated based on the proportion of agricultural land inside the boundary. Agricultural land cover classes were extracted from the Corine 2018 land cover dataset and used for the agricultural area calculations.
The following geospatial datasets are used for this analysis:
- County boundaries - (OS BoundaryLine)
- Postcode district areas - (OpenDoor Postcode Districts)
- Land Cover data - (Corine 2018)
#> Import county boundaries
#> Import ceremonial counties polygon layer from OS BoundaryLine dataset
counties.sw <- st_read(here("In", "Shape", "South_West.UPDATED.3.shp"), quiet = TRUE)
# glimpse(counties.sw)
#> Remove the deleted Bath and NE Somerset polygon (result of pre-geoprocessing in QGIS)
counties.sw <- counties.sw |>
filter(is.na(NAME_2))
#> Import postcode district boundary polygon data (source: https://www.opendoorlogistics.com/downloads/)
pcodes.gb <- st_read(here("In", "Shape", "Pcode_Districts_OpenDoor_2017.shp"), quiet = TRUE)
#> Import CORINE 2018 land cover data (polygons)
#> Data source: https://catalogue.ceh.ac.uk/documents/084e0bc6-e67f-4dad-9de6-0c698f60e34d
corine.gb <- st_read(here("In", "Shape", "corine_2018_GB.shp"), quiet = TRUE)
#> Select only agri land classes:
# 211 - Non-irrigated arable land
# 212 - Permanently irrigated land
# 213 - Rice fields
# 221 - Vineyards
# 222 - Fruit trees and berry plantations
# 223 - Olive groves
# 231 - Pastures
# 241 - Annual crops associated with permanent crops
# 242 - Complex cultivation patterns
# 243 - Land principally occupied by agriculture with significant areas of natural vegetation
# 244 - Agro-forestry areas
# 321 - Natural grasslands
# 322 - Moors and heathland
# 412 - Peatbogs
agri.land.classes <- c("211", "212", "213", "221", "222", "223", "231", "241", "242", "243", "244", "321", "322", "412")
#> Subset data based on land cover codes
corine.agri <- corine.gb |>
select(ID, CODE_18) |>
filter(CODE_18 %in% agri.land.classes)
#> Export agri data for detailed visual checking in QGIS
#> Remove previous shapefile export
unlink(here("Out", "Tests", "Corine_Agri.shp"))
unlink(here("Out", "Tests", "Corine_Agri.dbf"))
unlink(here("Out", "Tests", "Corine_Agri.prj"))
unlink(here("Out", "Tests", "Corine_Agri.shx"))
st_write(corine.agri, here("Out", "Tests", "Corine_Agri.shp"), quiet = TRUE)
#> Show an example plot of agri land extracted from Corine
#> Get Cornwall boundaries
cornwall.sf <- counties.sw |>
filter(NAME == "Cornwall")
#> Clip corine.gb to extent of Cornwall
corine.clip <- st_intersection(corine.agri,cornwall.sf)
#
# #> Previous static map (superseded by Leaflet map)
# #> Plot
# plot0 <- ggplot(data = cornwall.sf) +
# ggtitle("Agricultural land: Cornwall (extracted from Corine 2018)") +
# # theme_bw() +
# geom_sf() +
# geom_sf(data = corine.clip, fill = "green")
# #> Render on web page
# print(plot0)Figure 1.2.1 Extent of agricultural land (derived from Corine 2018)
#> This code chunk produces an interactive leafelt map of the SW region with Corine agri land shown
#> Subset counties.gb, selecting only Cornwall (inc Isles of Scilly), Devon, Somerset, and Dorset
#> Will also use this string in Section 1.3 loop
#> Create filter string (get names first!)
counties <- c("Cornwall", "Devon", "Dorset", "Somerset")
#> Create sf object of 4 counties
south.west <- counties.sw |>
filter(NAME %in% counties)
#> Import clipped (to SW region) dissolved layer of Corine agri
#> Pre-processed in QGIS and imported as process in R takes too long
corine.sw <- st_read(here("In", "Shape", "Corine.sw.clip.diss.simp.100.diss3.shp"), quiet = TRUE)
#> Convert layers to WGS84 for use with Leaflet
south.west <- st_transform(south.west, 4326)
corine.sw <- st_transform(corine.sw, 4326)
#> Create Leaflet map
leaflet() |>
addPolygons(data = corine.sw, fillOpacity = 0.5, color = "green", stroke = FALSE) |>
addPolygons(data = south.west, fillOpacity = 0, label = TRUE) |>
addTiles()